#ifndef __THREAD_THREAD_H
#define __THREAD_THREAD_H

#include "stdint.h"
#include "list.h"

// 自定义函数类型，它将在很多 线程函数 中作为形参类型
typedef void thread_func(void*);

// 进程或线程的状态
enum task_status {
    TASK_RUNNING, // 运行状态
    TASK_READY,   // 就绪状态
    TASK_BLOCKED, // 阻塞状态
    TASK_WAITING, // 等待状态(该状态也是阻塞状态的其中一种, 通过 wait() 让线程等待某项工作完成)
    TASK_HANGING, // 挂起状态
    TASK_DIED     // 死亡状态
};

/**
 * 中断栈
 * 此结构用于中断发生时保护现场
 * 任务(进程或现场) 被外部中断或软中断打断时，会按照此结构压入上下文寄存器
 * 此栈在线程自己的内核栈中位置固定，在页的最顶端（详细可以去看 thread.c 中的 xxxx 函数）
 */
struct intr_stack {
    uint32_t vec_no;	 // kernel.S 宏VECTOR中push %1压入的中断号
    uint32_t edi;
    uint32_t esi;
    uint32_t ebp;
    uint32_t esp_dummy;	 // 虽然pushad把esp也压入,但esp是不断变化的,所以会被popad忽略
    uint32_t ebx;
    uint32_t edx;
    uint32_t ecx;
    uint32_t eax;
    uint32_t gs;
    uint32_t fs;
    uint32_t es;
    uint32_t ds;

/* 以下由cpu从低特权级进入高特权级时压入 */
    uint32_t err_code;		 // err_code会被压入在eip之后
    void (*eip) (void);
    uint32_t cs;
    uint32_t eflags;
    void* esp;
    uint32_t ss;
};

/**
 * 线程栈
 * 线程自己的栈，用于存储线程中待执行的函数
 * 此结构在内核栈中的位置不固定
 * 用在 switch_to 函数时保存线程环境
 * 实际位置要看实际运行情况
 */
struct thread_stack {
    uint32_t ebp;
    uint32_t ebx;
    uint32_t edi;
    uint32_t esi;

    // 线程第一次执行时，eip 指向待调用的函数 kernel_thread
    // 其它时候，eip 是指向 witch_to 的返回地址
    void (*eip) (thread_func* func, void* func_arg);

    // 以下仅供第一次被调度商 CPU 时使用
    void (*unused_retaddr);
    thread_func* function; // 由 Kernel_thread 所调用的函数名
    void* func_arg;        // 由 Kernel_thread 所调用的函数所需的参数
};

// 进程或线程的 PCB，即程序控制块
struct task_struct {
    uint32_t* self_kstack;   // 各内核线程都用自己的内核栈
    enum task_status status; // 线程状态
    char name[16];           // 线程名
    uint8_t priority;        // 线程优先级 也就是在处理器上执行的时间数
    uint8_t ticks;           // 在处理器上执行的时间 初始值为 priority 递减到 0 表示本次所占用处理器的时间结束
                             // 递减到 0 后 由 priority 重置 ticks 即 ticks = priority
                            
    uint32_t elapsed_ticks;  // 该任务从第一次上处理器执行到最后一次执行完毕所用的总时间数，即任务完成所用总时长

    struct list_elem general_tag;  // 用于就绪队列中的结点
    struct list_elem all_list_tag; // 用于 thread_all_list 中的结点

    uint32_t* pgdir;         // 线程所处页表的虚拟地址
    uint32_t stack_magic;    // 用这串数字做栈的边界标记，用于检测栈的溢出
};

void thread_create(struct task_struct* pthread, thread_func function, void* func_arg);
void init_thread(struct task_struct* pthread, char* name, int prio);
struct task_struct* thread_start(char* name, int prio, thread_func function, void* func_arg);
struct task_struct* running_thread(void);
void schedule(void);
void thread_init(void);
void thread_block(enum task_status stat);
void thread_unblock(struct task_struct* pthread);
#endif
